<html>

<head>
<style>
.tabtop13 {
	margin-top: 13px;
}
.tabtop13 td{
	background-color:#ffffff;
	height:25px;
	line-height:150%;
}
.font-center{ text-align:center}
.btbg{background:#e9faff !important;}
.btbg1{background:#90b9c7 !important;}
.btbg2{background:#e3edf2 !important;}
.btbg3{background:#f1f7fa !important;}
.biaoti{
	font-family: 微软雅黑;
	font-size: 26px;
	font-weight: bold;
	border-bottom:1px dashed #CCCCCC;
	color: #255e95;
}
.titfont {
	
	font-family: 微软雅黑;
	font-size: 16px;
	font-weight: bold;
	color: #255e95;
	background: url(../images/ico3.gif) no-repeat 15px center;
	background-color:#e9faff;
}
.tabtxt2 {
	font-family: 微软雅黑;
	font-size: 14px;
	font-weight: bold;
	text-align: right;
	padding-right: 10px;
	color:#327cd1;
}
.tabtxt3 {
	font-family: 微软雅黑;
	font-size: 14px;
	padding-left: 15px;
	color: #000;
	margin-top: 10px;
	margin-bottom: 10px;
	line-height: 20px;
}

.ppl td {
  position: relative;
}
 
.ppl td:hover:after {
  position: absolute;
  margin-left: 10px;
  padding: 2px 10px;
  box-shadow: 0 2px 9px #999;
  background-color: #FFF;
  border-radius: 4px;
  color: #666;
  content: attr(title);
  z-index: 2;
  line-height: 20px;
  height: 20px;
}

</style>

</head>

<body>
    <div><span>请上传配置文件：</span><input type="file" id="configFile" ></div>
    <div><span>注：FR-对应分项的固定倍率  LL-对应分项的倍率下限</span></div>

    <div id="simulation5M"> </div>
    <div id="simulation10M"> </div>
    <div id="simulation25M"> </div>
    <div id="simulationRaid"> </div>

    <div align="center"><span>&nbsp;</span></div>
    <div align="center"><span>分时弹性模拟计算器</span></div>
    <div align="center"><span>@CopyRight StephZcj</span></div>
    <div align="center"><span>Version: 1.2.0</span></div>

    <script type="text/javascript">
        //配置的所有行
        var fileAllLine = [];
        //解析出高级配置
        var advancedConfig = {};
        var timeSperatedSize = 0;

        window.onload = function(){
            document.getElementById("configFile").addEventListener('change',function(){
                let reader = new FileReader();
                reader.readAsText(document.getElementById("configFile").files[0])
                reader.onload = function(){
                    let try1 = reader.result.split("\r\n");
                    let try2 = reader.result.split("\r");
                    let try3 = reader.result.split("\n");
                    if(try1.length > 10){
                        fileAllLine = try1;
                    }
                    if(try2.length > 10){
                        fileAllLine = try2;
                    }
                    if(try3.length > 10){
                        fileAllLine = try3;
                    }
                    for(let i = 0; i < fileAllLine.length; i++){
                        if(fileAllLine[i].startsWith("AutoBalance.advanced.")){
                            let lineSplit = fileAllLine[i].split("=");
                            advancedConfig[lineSplit[0].trim()] = lineSplit[1].trim();
                        }
                    }
                    for(let key in advancedConfig){
                        if(key == "AutoBalance.advanced.enable" ||
                        key == "AutoBalance.advanced.time.seperated.enable"){
                            continue;
                        }
                        if(key == "AutoBalance.advanced.time.seperated.point"){
                            let arrStart = ["00:00:00"];
                            let arr = advancedConfig[key].split("|");
                            for(let index in arr){
                                arr[index] = arr[index] + ":00";
                            }
                            timeSperatedSize = arr.length + 1;
                            let arrEnd = ["24:00:00"];
                            let newArr = arrStart.concat(arr).concat(arrEnd);
                            advancedConfig[key] = newArr;
                        }else{
                            let arr = advancedConfig[key].split("|");
                            for(let k in arr){
                                arr[k] = Number(arr[k]);
                            }
                            advancedConfig[key] = arr;
                        }
                    }
                    renderTable(5,"simulation5M");
                    renderTable(10,"simulation10M");
                    renderTable(25,"simulation25M");
                };
            })
        }

        /**
         * 渲染表格
         */
        function renderTable(maxPlayers, elementId){
            let finalHtml = '';
            finalHtml += '<table width="100%" border="0" cellspacing="1" cellpadding="4" bgcolor="#cccccc" class="tabtop13" align="center">'
            + getTableHeaderL1(maxPlayers) + getTableHeaderL2(maxPlayers) + getTableHeaderL3();

            switch (maxPlayers) {
                case 5:
                    for(let realPlayer=1; realPlayer<=maxPlayers; realPlayer++){
                        finalHtml += '<tr align="center">'
                            +'<td class="btbg3">'+realPlayer+'</td>'//人数
                        for(let timeIndex=0; timeIndex<timeSperatedSize; timeIndex++){
                            // 该时间片的全局倍率
                            let globalRate = advancedConfig["AutoBalance.advanced.rate.global"][timeIndex];
                            // N 人的拐点曲线
                            let inflectionPoint_5H = advancedConfig["AutoBalance.advanced.inflectionPoint.5H"][timeIndex];
                            let inflectionPoint_5 = advancedConfig["AutoBalance.advanced.inflectionPoint.5"][timeIndex];
                            //分项倍率--血量
                            let healthRate_H = advancedConfig["AutoBalance.advanced.rate.health.5H"][timeIndex];
                            let healthRate_PT  = advancedConfig["AutoBalance.advanced.rate.health.5"][timeIndex];
                            //分项倍率--伤害
                            let damageRate_H = advancedConfig["AutoBalance.advanced.rate.damage.5H"][timeIndex];
                            let damageRate_PT  = advancedConfig["AutoBalance.advanced.rate.damage.5"][timeIndex];
                            //HP倍率下限
                            let minHPModifier_H = advancedConfig["AutoBalance.advanced.MinHPModifier.5H"][timeIndex];
                            let minHPModifier_PT  = advancedConfig["AutoBalance.advanced.MinHPModifier.5"][timeIndex]; 
                            //伤害倍率下限
                            let minDamageModifier_H = advancedConfig["AutoBalance.advanced.MinDamageModifier.5H"][timeIndex];
                            let minDamageModifier_PT  = advancedConfig["AutoBalance.advanced.MinDamageModifier.5"][timeIndex];                           

                            //计算倍率
                            let ABMultiplier_PT = getAutoBalancedMultipiler(inflectionPoint_5, maxPlayers, realPlayer);
                            let ABMultiplier_H  = getAutoBalancedMultipiler(inflectionPoint_5H, maxPlayers, realPlayer);
                            let realHpMultipiler_H = getFinalMultipiler(globalRate,inflectionPoint_5H,maxPlayers,realPlayer,healthRate_H,minHPModifier_H);
                            let realHpMultipiler_PT = getFinalMultipiler(globalRate,inflectionPoint_5,maxPlayers,realPlayer,healthRate_PT,minHPModifier_PT);
                            let realDmgMultipiler_H = getFinalMultipiler(globalRate,inflectionPoint_5H,maxPlayers,realPlayer,damageRate_H,minDamageModifier_H);
                            let realDmgMultipiler_PT = getFinalMultipiler(globalRate,inflectionPoint_5,maxPlayers,realPlayer,damageRate_PT,minDamageModifier_PT);

                            let tdClass = "btbg3";
                            if( realPlayer%2 == 0 ){
                                tdClass = "btbg2";
                            }
                            finalHtml += ''
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_PT+'</td>'//PT血量弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realHpMultipiler_PT+'</td>'//PT血量综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_PT+'</td>'//PT伤害弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realDmgMultipiler_PT+'</td>'//PT伤害综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_H+'</td>'//H血量弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realHpMultipiler_H+'</td>'//H血量综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_H+'</td>'//H伤害弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realDmgMultipiler_H+'</td>'//H伤害综合倍率
                                ;

                        }
                        finalHtml +='</tr>'
                    }
                    break;
                case 10:
                    for(let realPlayer=1; realPlayer<=maxPlayers; realPlayer++){
                        finalHtml += '<tr align="center">'
                            +'<td class="btbg3">'+realPlayer+'</td>'//人数
                        for(let timeIndex=0; timeIndex<timeSperatedSize; timeIndex++){
                            // 该时间片的全局倍率
                            let globalRate = advancedConfig["AutoBalance.advanced.rate.global"][timeIndex];
                            // N 人的拐点曲线
                            let inflectionPoint_10H = advancedConfig["AutoBalance.advanced.inflectionPoint.Raid.10H"][timeIndex];
                            let inflectionPoint_10 = advancedConfig["AutoBalance.advanced.inflectionPoint.Raid.10"][timeIndex];
                            //分项倍率--血量
                            let healthRate_H = advancedConfig["AutoBalance.advanced.rate.health.Raid.10H"][timeIndex];
                            let healthRate_PT  = advancedConfig["AutoBalance.advanced.rate.health.Raid.10"][timeIndex];
                            //分项倍率--伤害
                            let damageRate_H = advancedConfig["AutoBalance.advanced.rate.damage.Raid.10H"][timeIndex];
                            let damageRate_PT  = advancedConfig["AutoBalance.advanced.rate.damage.Raid.10"][timeIndex];
                            //HP倍率下限
                            let minHPModifier_H = advancedConfig["AutoBalance.advanced.MinHPModifier.Raid.10H"][timeIndex];
                            let minHPModifier_PT  = advancedConfig["AutoBalance.advanced.MinHPModifier.Raid.10"][timeIndex]; 
                            //伤害倍率下限
                            let minDamageModifier_H = advancedConfig["AutoBalance.advanced.MinDamageModifier.Raid.10H"][timeIndex];
                            let minDamageModifier_PT  = advancedConfig["AutoBalance.advanced.MinDamageModifier.Raid.10"][timeIndex];                           

                            //计算倍率
                            let ABMultiplier_PT = getAutoBalancedMultipiler(inflectionPoint_10, maxPlayers, realPlayer);
                            let ABMultiplier_H  = getAutoBalancedMultipiler(inflectionPoint_10H, maxPlayers, realPlayer);
                            let realHpMultipiler_H = getFinalMultipiler(globalRate,inflectionPoint_10H,maxPlayers,realPlayer,healthRate_H,minHPModifier_H);
                            let realHpMultipiler_PT = getFinalMultipiler(globalRate,inflectionPoint_10,maxPlayers,realPlayer,healthRate_PT,minHPModifier_PT);
                            let realDmgMultipiler_H = getFinalMultipiler(globalRate,inflectionPoint_10H,maxPlayers,realPlayer,damageRate_H,minDamageModifier_H);
                            let realDmgMultipiler_PT = getFinalMultipiler(globalRate,inflectionPoint_10,maxPlayers,realPlayer,damageRate_PT,minDamageModifier_PT);

                            let tdClass = "btbg3";
                            if( realPlayer%2 == 0 ){
                                tdClass = "btbg2";
                            }
                            finalHtml += ''
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_PT+'</td>'//PT血量弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realHpMultipiler_PT+'</td>'//PT血量综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_PT+'</td>'//PT伤害弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realDmgMultipiler_PT+'</td>'//PT伤害综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_H+'</td>'//H血量弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realHpMultipiler_H+'</td>'//H血量综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_H+'</td>'//H伤害弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realDmgMultipiler_H+'</td>'//H伤害综合倍率
                                ;

                        }
                        finalHtml +='</tr>'
                    }
                    
                    break;
                case 25:
                    for(let realPlayer=1; realPlayer<=maxPlayers; realPlayer++){
                        finalHtml += '<tr align="center">'
                            +'<td class="btbg3">'+realPlayer+'</td>'//人数
                        for(let timeIndex=0; timeIndex<timeSperatedSize; timeIndex++){
                            // 该时间片的全局倍率
                            let globalRate = advancedConfig["AutoBalance.advanced.rate.global"][timeIndex];
                            // N 人的拐点曲线
                            let inflectionPoint_25H = advancedConfig["AutoBalance.advanced.inflectionPoint.Raid.25H"][timeIndex];
                            let inflectionPoint_25 = advancedConfig["AutoBalance.advanced.inflectionPoint.Raid.25"][timeIndex];
                            //分项倍率--血量
                            let healthRate_H = advancedConfig["AutoBalance.advanced.rate.health.Raid.25H"][timeIndex];
                            let healthRate_PT  = advancedConfig["AutoBalance.advanced.rate.health.Raid.25"][timeIndex];
                            //分项倍率--伤害
                            let damageRate_H = advancedConfig["AutoBalance.advanced.rate.damage.Raid.25H"][timeIndex];
                            let damageRate_PT  = advancedConfig["AutoBalance.advanced.rate.damage.Raid.25"][timeIndex];
                            //HP倍率下限
                            let minHPModifier_H = advancedConfig["AutoBalance.advanced.MinHPModifier.Raid.25H"][timeIndex];
                            let minHPModifier_PT  = advancedConfig["AutoBalance.advanced.MinHPModifier.Raid.25"][timeIndex]; 
                            //伤害倍率下限
                            let minDamageModifier_H = advancedConfig["AutoBalance.advanced.MinDamageModifier.Raid.25H"][timeIndex];
                            let minDamageModifier_PT  = advancedConfig["AutoBalance.advanced.MinDamageModifier.Raid.25"][timeIndex];                           

                            //计算倍率
                            let ABMultiplier_PT = getAutoBalancedMultipiler(inflectionPoint_25, maxPlayers, realPlayer);
                            let ABMultiplier_H  = getAutoBalancedMultipiler(inflectionPoint_25H, maxPlayers, realPlayer);
                            let realHpMultipiler_H = getFinalMultipiler(globalRate,inflectionPoint_25H,maxPlayers,realPlayer,healthRate_H,minHPModifier_H);
                            let realHpMultipiler_PT = getFinalMultipiler(globalRate,inflectionPoint_25,maxPlayers,realPlayer,healthRate_PT,minHPModifier_PT);
                            let realDmgMultipiler_H = getFinalMultipiler(globalRate,inflectionPoint_25H,maxPlayers,realPlayer,damageRate_H,minDamageModifier_H);
                            let realDmgMultipiler_PT = getFinalMultipiler(globalRate,inflectionPoint_25,maxPlayers,realPlayer,damageRate_PT,minDamageModifier_PT);

                            let tdClass = "btbg3";
                            if( realPlayer%2 == 0 ){
                                tdClass = "btbg2";
                            }
                            finalHtml += ''
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_PT+'</td>'//PT血量弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realHpMultipiler_PT+'</td>'//PT血量综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_PT+'</td>'//PT伤害弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realDmgMultipiler_PT+'</td>'//PT伤害综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_H+'</td>'//H血量弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realHpMultipiler_H+'</td>'//H血量综合倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+ABMultiplier_H+'</td>'//H伤害弹性倍率
                                +'<td class="'+tdClass+' ppl" title="'+realPlayer+'人">'+realDmgMultipiler_H+'</td>'//H伤害综合倍率
                                ;

                        }
                        finalHtml +='</tr>'
                    }
                    break;
                default:
                    break;
            }
            

            finalHtml += '</table>';
            document.getElementById(elementId).innerHTML = finalHtml;
        } 
        

        /**
         * 获取最终倍率
         * @param InflectionPoint 
         * @param maxPlayers
         * @param currPlayers
         * @param confBaseMultipiler
         * @param minMultipiler
         */
        function getFinalMultipiler(globalRate,InflectionPoint, maxPlayers, currPlayers, confBaseMultipiler, minMultipiler, isBoss){
            let defaultMultiplier = getAutoBalancedMultipiler(InflectionPoint, maxPlayers, currPlayers, isBoss);
            //最终公式是 配置的基础倍率*弹性倍率*全局倍率
            let realMultipiler = confBaseMultipiler * defaultMultiplier * globalRate;
            if (realMultipiler < minMultipiler){
                realMultipiler = minMultipiler;
            }
            return realMultipiler.toFixed(3);
        }

        /**
         * 获取弹性倍率
         * @param InflectionPoint 
         * @param maxPlayers
         * @param currPlayers
         * @param isBoss
         */
        function getAutoBalancedMultipiler(InflectionPoint, maxPlayers, currPlayers, isBoss){
            let InflectionValue = InflectionPoint * maxPlayers;
            if(isBoss){
                InflectionValue *= bossInflectionMult;
            }
            let diff = maxPlayers/5*1.5;
            //tanh的参数越小，返回的值越小，但不同点位速率不同（返回值越靠近1的地方，切线斜率越陡，表示参数只需变动一点点即可获得较大变动的返回值）
            //这里通过InflectionValue来控制，值越大，则说明队伍里只需减少一两个的玩家就能获得高额的数值减免
            let tanhParam = (currPlayers - InflectionValue)/diff;
            //这里+1和/2是为了把tanh取值范围控制在[0,1]
            let defaultMultiplier = (Math.tanh(tanhParam) + 1)/2;
            return defaultMultiplier.toFixed(3);
        }

        function getTableHeaderL1(maxPlayers){
            let level1 = '<tr class="btbg font-center titfont"><th colspan="' + (timeSperatedSize*8+1) +'">'+maxPlayers+'人弹性模拟</th></tr>';
            
            let level2 = '<tr class="btbg font-center titfont"><th rowspan="4">人数</th>';
            let timeSperatedArr = advancedConfig["AutoBalance.advanced.time.seperated.point"];
            for (let i = 0; i<timeSperatedSize; i++){
                level2 += '<th colspan="8">'+timeSperatedArr[i]+'-'+timeSperatedArr[i+1]+'（时段全局倍率:'+advancedConfig["AutoBalance.advanced.rate.global"][i]+'）</th>';
            }
            level2 += '</tr>';

            let level3 = '<tr class="btbg font-center titfont">';
            for (let i = 0; i<timeSperatedSize; i++){
                level3 += '<th colspan="4">'+maxPlayers+'PT</th><th colspan="4">'+maxPlayers+'H</th>';
            }
            level3 += '</tr>';
            return level1 + level2+ level3;
        }

        function getTableHeaderL2(maxPlayers){
            let level = '<tr class="btbg font-center titfont" align="center">';

             switch (maxPlayers) {
                case 5:
                    for (let i = 0; i<timeSperatedSize; i++){
                        level += '<th colspan="2">血量 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.health.5"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinHPModifier.5"][i]+'）</th>'
                        +'<th colspan="2">伤害 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.damage.5"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinDamageModifier.5"][i]+'）</th>'
                        +'<th colspan="2">血量 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.health.5H"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinHPModifier.5H"][i]+'）</th>'
                        +'<th colspan="2">伤害 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.damage.5H"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinDamageModifier.5H"][i]+'）</th>';
                    }
                    break;
                case 10:
                    for (let i = 0; i<timeSperatedSize; i++){
                        level += '<th colspan="2">血量 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.health.Raid.10"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinHPModifier.Raid.10"][i]+'）</th>'
                        +'<th colspan="2">伤害 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.damage.Raid.10"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinDamageModifier.Raid.10"][i]+'）</th>'
                        +'<th colspan="2">血量 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.health.Raid.10H"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinHPModifier.Raid.10H"][i]+'）</th>'
                        +'<th colspan="2">伤害 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.damage.Raid.10H"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinDamageModifier.Raid.10H"][i]+'）</th>';
                    } 
                    break;
                case 25:
                    for (let i = 0; i<timeSperatedSize; i++){
                        level += '<th colspan="2">血量 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.health.Raid.25"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinHPModifier.Raid.25"][i]+'）</th>'
                        +'<th colspan="2">伤害 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.damage.Raid.25"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinDamageModifier.Raid.25"][i]+'）</th>'
                        +'<th colspan="2">血量 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.health.Raid.25H"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinHPModifier.Raid.25H"][i]+'）</th>'
                        +'<th colspan="2">伤害 <br>（FR:'+advancedConfig["AutoBalance.advanced.rate.damage.Raid.25H"][i]+',LL:'+advancedConfig["AutoBalance.advanced.MinDamageModifier.Raid.25H"][i]+'）</th>';
                    } 
                    break;
                 default:
                    break;
             }   
            
            level += '</tr>';
            return level;
        }

        function getTableHeaderL3(){
            let level = '<tr class="btbg font-center titfont" align="center">';
            for (let i = 0; i<timeSperatedSize; i++){
                level += '<th>弹性倍率</th><th>最终倍率</th>'
                +'<th>弹性倍率</th><th>最终倍率</th>'
                +'<th>弹性倍率</th><th>最终倍率</th>'
                +'<th>弹性倍率</th><th>最终倍率</th>';
            }
            level += '</tr>';
            return level;
        }

        

    </script>

</body>







</html>